package org.dinqy.impl;

import java.util.ArrayList;
import java.util.List;

import org.dinqy.ClauseBean;
import org.dinqy.ClauseBeanVisitor;
import org.dinqy.ClauseType;
import org.dinqy.LimitOffsetClauseBean;
import org.dinqy.OrderClauseBean;
import org.dinqy.QueryBean;
import org.dinqy.QueryBuilder;
import org.dinqy.WhereClauseBean;

/**
 * @author armandino (at) gmail.com
 */
public final class QueryBuilderImpl implements QueryBuilder, ClauseBeanVisitor {
    private final Class<?> entityClass;
    private final List<ClauseBean> clauseBeans;
    
    private final StringBuilder queryBuffer = new StringBuilder();
    private final List<Object> queryArguments = new ArrayList<Object>();
    private Integer limit;
    private Integer offset;
    
    public QueryBuilderImpl(Class<?> entityClass, List<ClauseBean> clauseBeans) {
        this.entityClass = entityClass;
        this.clauseBeans = clauseBeans;
    }
    
    public void visit(WhereClauseBean clauseBean) {
        queryBuffer.append(clauseBean.toJPQL());
        queryArguments.addAll(clauseBean.getClauseArguments());
    }
    
    public void visit(OrderClauseBean clauseBean) {
        queryBuffer.append(clauseBean.toJPQL());
    }
    
    public void visit(LimitOffsetClauseBean clauseBean) {
        if(clauseBean.getClauseType() == ClauseType.LIMIT)
            limit = clauseBean.getValue();
        if(clauseBean.getClauseType() == ClauseType.OFFSET)
            offset = clauseBean.getValue();
    }
    
    public QueryBean getQueryBean() {
        appendSelectFromToQueryBuffer();
        appendClausesToQueryBuffer();
        return new QueryBean(queryBuffer, queryArguments, limit, offset);
    }
    
    public QueryBean getCountQueryBean() {
        appendCountToQueryBuffer();
        appendClausesToQueryBuffer();
        return new QueryBean(queryBuffer, queryArguments, limit, offset);
    }
    
    private void appendSelectFromToQueryBuffer() {
        final String entityName = entityClass.getSimpleName();
        queryBuffer.append("select obj from ").append(entityName).append(" obj");
    }
    
    private void appendCountToQueryBuffer() {
        final String entityName = entityClass.getSimpleName();
        queryBuffer.append("select count(obj) from ").append(entityName).append(" obj");
    }
    
    private void appendClausesToQueryBuffer() {
        for(ClauseBean clauseBean : clauseBeans) {
            clauseBean.accept(this);
        }
    }
}
